home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-1.iso / games / ted5.zip / IGRABSRC.ZIP / IGRAB.C < prev    next >
C/C++ Source or Header  |  1993-02-04  |  30KB  |  1,306 lines

  1. ////////////////////////////////////////////////////////////
  2. //
  3. // IGRAB - Multi-Graphics-Mode, Multi-Format, Fast BitMap Grabber
  4. // by John Romero (C) 1991 Id Software
  5. //
  6. ////////////////////////////////////////////////////////////
  7. #include "igrab.h"
  8. #pragma hdrstop
  9.  
  10. //
  11. // VARS
  12. //
  13. time_t tblock;
  14. LBMtype CurrentLBM;
  15. PicStruct far *PicTable,far *PicmTable;
  16. SprStruct SpriteTable[MAXSPRITES];
  17. FILE *fp;
  18. grabtype type;
  19. graphtype gmode;
  20. DataStruct Data[11]={{0,{0,0,0,0},0},        // font
  21.              {0,{0,0,0,0},0},       // fontm
  22.              {0,{16,32,64,0},0},    // tile8
  23.              {0,{32,40,128,0},0},    // tile8m
  24.              {0,{64,128,256,0},0},    // tile16
  25.              {0,{128,160,512,0},0},    // tile16m
  26.              {0,{256,512,1024,0},0},    // tile32
  27.              {0,{512,640,2048,0},0},    // tile32m
  28.              {0,{0,0,0,0},0},        // pic
  29.              {0,{0,0,0,0},0},        // picm
  30.              {0,{0,0,0,0},0}};        // sprite
  31.  
  32. extern char typestr[5];
  33.  
  34. char picname[64],huge *Sparse;
  35.  
  36. char huge *PicNames,huge *SpriteNames,huge *PicMNames,huge *ChunkNames,
  37.      huge *MiscNames,huge *MiscFNames;
  38.  
  39. unsigned char format[2],scriptname[64],dest[13],string[80],ext[10],huge *lbmscreen,
  40.      huge *databuffer,huge *maskscreen,ScreenColor,
  41.      typelist[17][10]={"FONT","FONTM","TILE8","TILE8","TILE8M","TILE8M","TILE16","TILE16",
  42.        "TILE16M","TILE16M","TILE32","TILE32","TILE32M","TILE32M","PIC","PICM","SPRITE"},
  43.      huge *T8bit,huge *T16bit,huge *T32bit,path[64],NumMisc;
  44. long offset,size,fsize,tile8off,tile8moff,tile16off,tile16moff,
  45.      tile32off,tile32moff,picoff,picmoff,spriteoff,fontoff,fontmoff,
  46.      FontOffs[MAXFONT],far *PicOffs,SpriteOffs[MAXSPRITES],FontMOffs[MAXFONT],
  47.      far *PicMOffs,bufmax,comp_size;
  48. unsigned begin,j,i,gotstr,frac,temp,keycheck,compress,
  49.      end,gottiles,globalx,globaly,globalmaxh,nostacking,noshow,shifts,
  50.      fastgrab,totalobjects,leavetmp,cmpt8,genobj,ChunkStart[MAXSPRITES/8],
  51.      ChunkEnd[MAXSPRITES/8],whichchunk,ChunkType[MAXSPRITES/8],bit,
  52.      T8whichbit,T16whichbit,T32whichbit,setbit,lumpactive,SkipToStart,
  53.      Do4offs,ModeX,PicAmount;
  54.  
  55. int handle;
  56.  
  57.  
  58. ////////////////////////////////////////////////////////////
  59. //
  60. // IGRAB start
  61. //
  62. ////////////////////////////////////////////////////////////
  63. void main(int argc,char **argv)
  64. {
  65.  //
  66.  // make sure we clear the Huffman compression array
  67.  //
  68.  
  69.  settext();
  70.  randomize();
  71.  memset(&counts,0,sizeof(counts));
  72.  DeleteTmpFiles();
  73.  
  74.  clrscr();
  75.  textcolor(15);
  76.  textbackground(1);
  77.  cprintf("%s\r\n",TITLESTR);
  78.  textbackground(0);
  79.  
  80.  if (argc<2)
  81.    {
  82.     printf("Expected format: IGRAB <format> [options] <filename>\n");
  83.     printf("<format>    = -E for EGA, -V for VGA graphics mode, -C for CGA.\n");
  84.     printf("<options>    = -NS for No Stacking of graphics while displaying\n");
  85.     printf("        = -OFF for turning graphics display off\n");
  86.     printf("        = -F for FastGrab (no keypress per screen)\n");
  87.     printf("        = -NUM=<value> to specify a larger offset array if\n");
  88.     printf("          you happen to have more than %d objects combined.\n",MAXOFFS);
  89.     printf("        = -L to leave all .TMP files intact after compression\n");
  90.     printf("        = -T8 to compress TILE8/Ms individually\n");
  91.     printf("        = -OBJ to generate a linkable .OBJ header file\n");
  92.     printf("        = -BIT to generate a packed-bit array for all\n");
  93.     printf("          foreground tiles that don't need a mask.\n");
  94.     printf("        = -PATH=<string> to specify a pathname where\n");
  95.     printf("          the .LBM screens can be found. Only for loading.\n");
  96.     printf("        = -4 to generate 4-byte chunk offsets, instead of 3.\n");
  97.     printf("        = -HUGE to grab EGA 640x350 graphics\n");
  98.     printf("        = -PICS=<value> to grab more than %d PIC/Ms\n",MAXPICS);
  99.     printf("        = -X to munge VGA PIC/Ms and SPRITEs\n");
  100.     printf("<filename>    = filename of the IGRAB Script File\n");
  101.     exit(1);
  102.    }
  103.  
  104.  PicAmount=MAXPICS;
  105.  totalobjects=MAXOFFS;
  106.  maskscreen=lbmscreen=NULL;
  107.  bufmax=BUFFERSIZE;
  108.  comp_size=MAXCOMPSIZE;
  109.  
  110.  /////////////////////////////////////////////////////////
  111.  //
  112.  // CommandLine "parser"
  113.  //
  114.  /////////////////////////////////////////////////////////
  115.  for (i=1;i<argc;i++)
  116.    {
  117.     argv[i]=strupr(argv[i]);
  118.     if (argv[i][0]=='/' || argv[i][0]=='-')
  119.       argv[i]++;
  120.  
  121.     if ((!strcmp(argv[i],"E")) ||
  122.     (!strcmp(argv[i],"V")) ||
  123.     (!strcmp(argv[i],"C")))
  124.       format[0]=argv[i][0];
  125.     else
  126.     if (!strcmp(argv[i],"NS"))
  127.       nostacking=1;
  128.     else
  129.     if (!strcmp(argv[i],"OFF"))
  130.       noshow=1;
  131.     else
  132.     if (!strcmp(argv[i],"F"))
  133.       fastgrab=1;
  134.     else
  135.     if (!strncmp(argv[i],"NUM=",4))
  136.       totalobjects=atoi(argv[i]+4);
  137.     else
  138.     if (!strncmp(argv[i],"PICS=",5))
  139.       PicAmount=atoi(argv[i]+5);
  140.     else
  141.     if (!strcmp(argv[i],"L"))
  142.       leavetmp=1;
  143.     else
  144.     if (!strcmp(argv[i],"T8"))
  145.       cmpt8=1;
  146.     else
  147.     if (!strcmp(argv[i],"OBJ"))
  148.       genobj=1;
  149.     else
  150.     if (!strcmp(argv[i],"BIT"))
  151.       bit=1;
  152.     else
  153.     if (!strcmp(argv[i],"4"))
  154.       Do4offs=1;
  155.     else
  156.     if (!strncmp(argv[i],"HUGE",4))
  157.       {
  158.        bufmax=BUFFER1SIZE;
  159.        comp_size=MAXCOMP1SIZE;
  160.       }
  161.     else
  162.     if (!strcmp(argv[i],"X"))
  163.       ModeX=1;
  164.     else
  165.     if (!strncmp(argv[i],"PATH=",5))
  166.       {
  167.        strcpy(path,argv[i]+5);
  168.        strcat(path,"\\");
  169.       }
  170.     else
  171.       strcpy(scriptname,argv[i]);
  172.    }
  173.  
  174.  
  175.  //
  176.  // DONE PARSING COMMAND-LINE ARGUMENTS
  177.  //
  178.  if (format[0]!='C' && format[0]!='E' && format[0]!='V')
  179.    errout("The graphics type can ONLY be CGA,EGA or VGA!\n");
  180.  
  181.  switch(format[0])
  182.    {
  183.     case 'C': gmode=CGA; break;
  184.     case 'E': gmode=EGA; break;
  185.     case 'V': gmode=VGA;
  186.    }
  187.  
  188.  if (gmode!=VGA && ModeX)
  189.    errout("Can't munge non-VGA graphics!\n");
  190.  
  191.  if (noshow)    // if screen is OFF, just blast thru!
  192.    fastgrab=1;
  193.  
  194.  //
  195.  // ALLOCATE BIT-ARRAY MEMORY
  196.  //
  197.  if (bit)
  198.    {
  199.     if (cmpt8)
  200.       if ((T8bit=(char huge *)farmalloc(NUMBITARRAY))==NULL)
  201.     errout("Not enough memory for BITARRAY for TILE8's!");
  202.     if ((T16bit=(char huge *)farmalloc(NUMBITARRAY))==NULL)
  203.       errout("Not enough memory for BITARRAY for TILE16's!");
  204.     if ((T32bit=(char huge *)farmalloc(NUMBITARRAY))==NULL)
  205.       errout("Not enough memory for BITARRAY for TILE32's!");
  206.  
  207.     for (i=0;i<NUMBITARRAY;i++)
  208.       T16bit[i]=T32bit[i]=0;
  209.    }
  210.  
  211.  if ((fp=fopen(scriptname,"rb"))==NULL)
  212.    {
  213.     char string[80]="Having problems opening ";
  214.  
  215.     strcat(string,scriptname);
  216.     strcat(string,"!");
  217.     errout(string);
  218.    }
  219.  
  220.  //
  221.  // Initialize stuff
  222.  //
  223.  
  224.  PicTable=farmalloc(PicAmount*sizeof(PicStruct));
  225.  PicmTable=farmalloc(PicAmount*sizeof(PicStruct));
  226.  PicOffs=farmalloc(PicAmount*4);
  227.  PicMOffs=farmalloc(PicAmount*4);
  228.  shifts=4;
  229.  
  230.  //
  231.  // The "8L" takes up "font/m,tile8/m,tile16/m & tile32/m spots
  232.  //
  233.  if ((Sparse=(char huge *)farmalloc(8L*totalobjects))==NULL)
  234.    errout("Not enough memory for SPARSE table allocation!");
  235.  
  236.  if ((databuffer=(char huge *)farmalloc(bufmax))==NULL)
  237.    errout("Memory allocation for data buffer failed!");
  238.  
  239.  frac=1;
  240.  keycheck=end=offset=begin=gotstr=0;
  241.  
  242.  if (!noshow)
  243.    switch(format[0])
  244.      {
  245.       case 'C': videomode(2); break;
  246.       case 'E': videomode(4); break;
  247.       case 'V': videomode(8); break;
  248.      }
  249.  
  250.  textbackground(1);
  251.  textcolor(14);
  252.  DispStatusScreen();
  253.  window(2,8,78,19);
  254.  
  255.  PicNames=(char huge *)farmalloc((long)PicAmount*NAMELEN);
  256.  PicMNames=(char huge *)farmalloc((long)PicAmount*NAMELEN);
  257.  SpriteNames=(char huge *)farmalloc((long)MAXSPRITES*NAMELEN);
  258.  ChunkNames=farmalloc((long)MAXSPRITES/8*CHKNAMELEN);
  259.  MiscNames=farmalloc((long)MAXPICS*NAMELEN);
  260.  MiscFNames=farmalloc((long)MAXPICS*FNAMELEN);
  261.  
  262.  if (!PicNames || !PicMNames || !SpriteNames || !ChunkNames || !MiscNames || !MiscFNames)
  263.    errout("Not enough memory for Name arrays!");
  264.  
  265.  /////////////////////////////////////////////////////////
  266.  //
  267.  // Parse script file
  268.  //
  269.  /////////////////////////////////////////////////////////
  270.  
  271.  while(bioskey(1))
  272.    bioskey(0);
  273.  
  274.  while(1)
  275.    {
  276.     int ready,grabbed;
  277.  
  278.     //
  279.     // FIRST, SEARCH FOR "START ..."
  280.     //
  281.  
  282.     ready=0;
  283.  
  284.     do {
  285.     fpos_t position;
  286.  
  287.     fgetpos(fp,&position);
  288.     fsetpos(fp,&position);
  289.  
  290.     if (!gotstr)
  291.       fgets(string,80,fp);
  292.     else
  293.       gotstr=0;
  294.  
  295.     if (!end)
  296.       for (i=0;i<strlen(string);i++)
  297.         if (string[i]=='\x1a')
  298.           errout("You didn't put an END at the end of your script!");
  299.  
  300.     strupr(string);
  301.  
  302.     //
  303.     // HANDLE "BEGIN"
  304.     //
  305.     if (!strncmp(string,"BEGIN",5))
  306.       {
  307.        begin=1;
  308.        strcpy(ext,string+6);
  309.        for (i=0;i<strlen(ext);i++)
  310.          if (ext[i]=='\r' || ext[i]=='\n')
  311.            ext[i]=0;
  312.        continue;
  313.       }
  314.  
  315.     //
  316.     // HANDLE "FRAC"
  317.     //
  318.  
  319.     if (!strncmp(string,"FRAC",4))
  320.       {
  321.        frac=atoi(string+5);
  322.        continue;
  323.       }
  324.  
  325.     //
  326.     // HANDLE "SHIFTS"
  327.     //
  328.  
  329.     if (!strncmp(string,"SHIFTS",6))
  330.       {
  331.        shifts=atoi(string+7);
  332.        continue;
  333.       }
  334.  
  335.     //
  336.     // HANDLE "START"
  337.     //
  338.  
  339.     if (!strncmp(string,"START",5))
  340.       {
  341.        if (!begin)
  342.          errout("You must first BEGIN!");
  343.  
  344.        grabbed=0;
  345.  
  346.        FindType(string+6);
  347.        SkipToStart=0;
  348.        ready++;
  349.        continue;
  350.       }
  351.  
  352.     //
  353.     // HANDLE "END"
  354.     //
  355.  
  356.     if (!strncmp(string,"END",3))
  357.       FinishUp();
  358.  
  359.     //
  360.     // HANDLE "EXTERN"
  361.     //
  362.     // THE "MiscNames" HOLD THE USER NAMES,
  363.     // THE "MiscFNames" HOLD THE FILENAMES OF THE DATA
  364.     //
  365.  
  366.     if (!strncmp(string,"EXTERN",6))
  367.       {
  368.        char *s1,*s2,comp[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  369.                    "abcdefghijklmnopqrstuvwxyz_",
  370.        comp1[]=",\x9\r\n",*s3,huge *tempdata;
  371.        long len;
  372.  
  373.  
  374.        s1=strpbrk(string+6,comp);
  375.        s2=strpbrk(s1,comp1);
  376.        *s2++=0;
  377.        s2=strpbrk(s2,comp);
  378.        s3=strpbrk(s2,comp1);
  379.        *s3=0;
  380.  
  381.        _fstrcpy((char far *)MiscNames+NumMisc*NAMELEN,(char far *)s1);
  382.        _fstrcpy((char far *)MiscFNames+NumMisc*NAMELEN,(char far *)s2);
  383.  
  384.        len=filelen(s2);
  385.        tempdata=farmalloc(len);
  386.        if (access(s2,0))
  387.        {
  388.         char errst[60]="The external file '";
  389.         strcat(errst,s2);
  390.         strcat(errst,"' cannot be found!");
  391.         errout(errst);
  392.        }
  393.  
  394.        LoadFile(s2,tempdata,0,0);
  395.        CountBytes((unsigned char huge *)tempdata,len);
  396.        farfree((void far *)tempdata);
  397.  
  398.        NumMisc++;
  399.       }
  400.  
  401.  
  402.        } while(!ready);
  403.  
  404.     ////////////////////////////////////////////////////
  405.     ////////////////////////////////////////////////////
  406.     //
  407.     // FOUND "START". TIME TO LOAD SCREENS & GRAB STUFF
  408.     //
  409.     ////////////////////////////////////////////////////
  410.     ////////////////////////////////////////////////////
  411.  
  412.     offset=ready=0;
  413.     if (bioskey(1))
  414.       bioskey(0);
  415.  
  416.     do {
  417.     fpos_t position;
  418.  
  419.     fgetpos(fp,&position);
  420.     fsetpos(fp,&position);
  421.  
  422.     fgets(string,80,fp);
  423.     strupr(string);
  424.  
  425.     /////////////////////////////////////////////
  426.     //
  427.     // HANDLE "EXTERN"
  428.     //
  429.     // THE "MiscNames" HOLD THE USER NAMES,
  430.     // THE "MiscFNames" HOLD THE FILENAMES OF THE DATA
  431.     //
  432.     /////////////////////////////////////////////
  433.  
  434.     if (!strncmp(string,"EXTERN",6))
  435.       {
  436.        char *s1,*s2,comp[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  437.                    "abcdefghijklmnopqrstuvwxyz_",
  438.        comp1[]=",\x9\r\n",*s3,huge *tempdata;
  439.        long len;
  440.  
  441.  
  442.        s1=strpbrk(string+6,comp);
  443.        s2=strpbrk(s1,comp1);
  444.        *s2++=0;
  445.        s2=strpbrk(s2,comp);
  446.        s3=strpbrk(s2,comp1);
  447.        *s3=0;
  448.  
  449.        _fstrcpy((char far *)MiscNames+NumMisc*NAMELEN,(char far *)s1);
  450.        _fstrcpy((char far *)MiscFNames+NumMisc*NAMELEN,(char far *)s2);
  451.  
  452.        len=filelen(s2);
  453.        tempdata=farmalloc(len);
  454.  
  455.        if (access(s2,0))
  456.        {
  457.         char errst[60]="The external file '";
  458.         strcat(errst,s2);
  459.         strcat(errst,"' cannot be found!");
  460.         errout(errst);
  461.        }
  462.  
  463.        LoadFile(s2,tempdata,0,0);
  464.        CountBytes((unsigned char huge *)tempdata,len);
  465.        farfree((void far *)tempdata);
  466.  
  467.        NumMisc++;
  468.       }
  469.  
  470.     /////////////////////////////////////////////
  471.     //
  472.     // FRAC keyword
  473.     //
  474.     /////////////////////////////////////////////
  475.     if (!strncmp(string,"FRAC",4))
  476.       {
  477.        frac=atoi(string+5);
  478.        continue;
  479.       }
  480.  
  481.     /////////////////////////////////////////////
  482.     //
  483.     // LOAD keyword
  484.     //
  485.     /////////////////////////////////////////////
  486.     if (!strncmp(string,"LOAD",4))
  487.       {
  488.        LoadKeyword(string+5,grabbed);
  489.        globalx=globaly=globalmaxh=0;
  490.        continue;
  491.       }
  492.  
  493.     /////////////////////////////////////////////
  494.     //
  495.     // HANDLE "LUMP"
  496.     //
  497.     /////////////////////////////////////////////
  498.  
  499.     if (!strncmp(string,"LUMP",4))
  500.       {
  501.        int newtype[17]={FONT,FONTM,TILE8,TILE8,TILE8M,TILE8M,
  502.         TILE16,TILE16,TILE16M,TILE16M,TILE32,TILE32,
  503.         TILE32M,TILE32M,PIC,PICM,SPRITE};
  504.  
  505.        if (lumpactive)
  506.          {
  507.           char erstr[200]="You tried to start a LUMP before ending the current lump ";
  508.           _fstrcat((char far *)erstr,(char far *)ChunkNames+whichchunk*CHKNAMELEN);
  509.           strcat(erstr,"!");
  510.           errout(erstr);
  511.          }
  512.  
  513.        _fmemcpy((char far *)ChunkNames+whichchunk*CHKNAMELEN,(char far *)string+5,CHKNAMELEN);
  514.        *(ChunkNames+whichchunk*CHKNAMELEN+CHKNAMELEN-1)=0;
  515.        ChunkType[whichchunk]=newtype[type];
  516.        ChunkStart[whichchunk]=Data[ChunkType[whichchunk]].num;
  517.        lumpactive=1;
  518.        continue;
  519.       }
  520.  
  521.     /////////////////////////////////////////////
  522.     //
  523.     // HANDLE "SHIFTS"
  524.     //
  525.     /////////////////////////////////////////////
  526.  
  527.     if (!strncmp(string,"SHIFTS",6))
  528.       {
  529.        shifts=atoi(string+7);
  530.        continue;
  531.       }
  532.  
  533.     /////////////////////////////////////////////
  534.     //
  535.     // HANDLE "ENDLUMP"
  536.     //
  537.     /////////////////////////////////////////////
  538.  
  539.     if (!strncmp(string,"ENDLUMP",7))
  540.       {
  541.        if (!lumpactive)
  542.          errout("You can't ENDLUMP when one isn't started!");
  543.  
  544.        ChunkEnd[whichchunk]=Data[ChunkType[whichchunk]].num-1;
  545.        whichchunk++;
  546.        lumpactive=0;
  547.        continue;
  548.       }
  549.  
  550.     /////////////////////////////////////////////
  551.     //
  552.     // GRAB keyword
  553.     //
  554.     /////////////////////////////////////////////
  555.     if (!strncmp(string,"GRAB",4))
  556.       {
  557.        sound(1500);
  558.        switch(type)
  559.          {
  560.           case FONTTYPE:
  561.           case FONTMTYPE:
  562.         GrabFont(type);
  563.         grabbed++;
  564.         break;
  565.           case TILE8TYPE:
  566.           case TILE8MTYPE:
  567.           case ALT8TYPE:
  568.           case ALT8MTYPE:
  569.           case TILE16TYPE:
  570.           case TILE16MTYPE:
  571.           case ALT16TYPE:
  572.           case ALT16MTYPE:
  573.           case TILE32TYPE:
  574.           case TILE32MTYPE:
  575.           case ALT32TYPE:
  576.           case ALT32MTYPE:
  577.         if (!maskscreen &&
  578.             (type==TILE8MTYPE || type==ALT8MTYPE ||
  579.              type==TILE16MTYPE || type==ALT16MTYPE ||
  580.              type==TILE32MTYPE || type==ALT32MTYPE))
  581.           errout("You haven't loaded a mask screen for TILEM yet!");
  582.  
  583.         nosound();
  584.         GrabTile(type);
  585.         grabbed++;
  586.         break;
  587.           case PICTYPE:
  588.           case PICMTYPE:
  589.         if (!maskscreen && type==PICMTYPE)
  590.           errout("You haven't loaded a mask screen for PICM yet!");
  591.  
  592.         GrabPics(type);
  593.         grabbed++;
  594.         break;
  595.           case SPRITETYPE:
  596.         GrabSprites();
  597.         grabbed++;
  598.         break;
  599.          }
  600.        nosound();
  601.        continue;
  602.       }
  603.  
  604.  
  605.     /////////////////////////////////////////////
  606.     //
  607.     // Check for end of script or start of another datatype
  608.     //
  609.     /////////////////////////////////////////////
  610.     if (!strncmp(string,"START",5) ||
  611.         !strncmp(string,"END",3))
  612.       {
  613.        //
  614.        // save off data for current type, if any is left
  615.        //
  616.        FlushData();
  617.        if (!strncmp(string,"END",3))
  618.          end=1;
  619.  
  620.        gotstr++;
  621.        ready++;
  622.       }
  623.  
  624.        } while (!ready);
  625.  
  626.     //
  627.     // GET A KEYPRESS
  628.     //
  629.     if ((!fastgrab) && grabbed)
  630.       {
  631.        int key;
  632.  
  633.        if (bioskey(1))
  634.      bioskey(0);
  635.  
  636.        if (!SkipToStart)
  637.        {
  638.     key=bioskey(0);
  639.  
  640.     switch(key&255)
  641.     {
  642.      case 13:
  643.        SkipToStart=1;
  644.        break;
  645.      case 27:
  646.        errout("IGRAB ABORTED!");
  647.      case  9:
  648.        if (!noshow)
  649.        {
  650.         settext();
  651.         DispStatusScreen();
  652.         fastgrab=noshow=1;
  653.        }
  654.     }
  655.        }
  656.       }
  657.  
  658.     switch(bioskey(1)>>8)
  659.     {
  660.      case 1:
  661.        errout("IGRAB ABORTED!");
  662.      case 15:
  663.        if (!noshow)
  664.        {
  665.     settext();
  666.     DispStatusScreen();
  667.     fastgrab=noshow=1;
  668.        }
  669.     }
  670.    }
  671. }
  672. // END OF MAIN
  673.  
  674.  
  675. ////////////////////////////////////////////////////////////
  676. //
  677. // Check for out-of-bounds in databuffer
  678. //
  679. ////////////////////////////////////////////////////////////
  680. void CheckBuffer(void)
  681. {
  682.  if (offset>bufmax)
  683.    {
  684.     settext();
  685.     printf("ERROR!: The %cGA data buffer is too small!\n",format[0]);
  686.     printf("Contact John Romero for a full refund!\n");
  687.     nosound();
  688.     exit(1);
  689.    }
  690.  
  691.  //
  692.  // IF MORE THAN 80% OF DATABUFFER IS FULL, FLUSH IT!
  693.  //
  694.  if (offset>4L*(bufmax/5))
  695.    FlushData();
  696. }
  697.  
  698.  
  699. ////////////////////////////////////////////////////////////
  700. //
  701. // Flush all PIC,PICM or SPRITE data to disk!
  702. //
  703. ////////////////////////////////////////////////////////////
  704. void FlushData(void)
  705. {
  706.  if (offset)
  707.    {
  708.     CountBytes(databuffer,offset);
  709.     switch(type)
  710.       {
  711.        case PICTYPE:
  712.      AddDataToFile("PIC");
  713.      break;
  714.        case PICMTYPE:
  715.      AddDataToFile("PICM");
  716.      break;
  717.        case SPRITETYPE:
  718.      AddDataToFile("SPRITE");
  719.      break;
  720.        case TILE8TYPE:
  721.        case ALT8TYPE:
  722.      AddDataToFile("TILE8");
  723.      break;
  724.        case TILE8MTYPE:
  725.        case ALT8MTYPE:
  726.      AddDataToFile("TILE8M");
  727.      break;
  728.        case TILE16TYPE:
  729.        case ALT16TYPE:
  730.      AddDataToFile("TILE16");
  731.      break;
  732.        case TILE16MTYPE:
  733.        case ALT16MTYPE:
  734.      AddDataToFile("TILE16M");
  735.      break;
  736.        case TILE32TYPE:
  737.        case ALT32TYPE:
  738.      AddDataToFile("TILE32");
  739.      break;
  740.        case TILE32MTYPE:
  741.        case ALT32MTYPE:
  742.      AddDataToFile("TILE32M");
  743.      break;
  744.  
  745.        default:
  746.      errout("Tried to FLUSHDATA for a type not supported!");
  747.       }
  748.    }
  749. }
  750.  
  751.  
  752. ////////////////////////////////////////////////////////////
  753. //
  754. // Delete all the temp files we're gonna use
  755. //
  756. ////////////////////////////////////////////////////////////
  757. void DeleteTmpFiles(void)
  758. {
  759.  unlink("FONT.TMP");
  760.  unlink("FONTM.TMP");
  761.  unlink("TILE8.TMP");
  762.  unlink("TILE8M.TMP");
  763.  unlink("TILE16.TMP");
  764.  unlink("TILE16M.TMP");
  765.  unlink("TILE32.TMP");
  766.  unlink("TILE32M.TMP");
  767.  unlink("PIC.TMP");
  768.  unlink("PICM.TMP");
  769.  unlink("SPRITE.TMP");
  770. }
  771.  
  772.  
  773. ////////////////////////////////////////////////////////////
  774. //
  775. // Add data in DATABUFFER to temp file
  776. //
  777. ////////////////////////////////////////////////////////////
  778. void AddDataToFile(char *filename)
  779. {
  780.  int handle;
  781.  long olength;
  782.  char newname[20];
  783.  
  784.  strcpy(newname,filename);
  785.  strcat(newname,".TMP");
  786.  
  787.  if ((handle=open(newname,O_BINARY))==-1)
  788.    olength=0;
  789.  else
  790.    {
  791.     olength=filelength(handle);
  792.     close(handle);
  793.    }
  794.  
  795.  SaveFile(newname,databuffer,offset,olength);
  796.  offset=0;
  797. }
  798.  
  799.  
  800. ////////////////////////////////////////////////////////////
  801. //
  802. // Set text mode
  803. //
  804. ////////////////////////////////////////////////////////////
  805. void settext(void)
  806. {
  807.  _AX=3;
  808.  geninterrupt(0x10);
  809. }
  810.  
  811.  
  812. ////////////////////////////////////////////////////////////
  813. //
  814. // Save a *LARGE* file from a FAR buffer!
  815. // by John Romero (C) 1991 Id Software
  816. //
  817. ////////////////////////////////////////////////////////////
  818. void SaveFile(char *filename,char huge *buffer, long size,long offset)
  819. {
  820.  struct dfree disk;
  821.  unsigned int handle,buf1,buf2,offlo,offhi,sizelo,sizehi;
  822.  
  823.  getdfree(0,&disk);
  824.  if ((long)disk.df_avail*disk.df_bsec*disk.df_sclus<size)
  825.    errout("Not enough disk space!");
  826.  
  827.  buf1=FP_OFF(buffer);
  828.  buf2=FP_SEG(buffer);
  829.  offlo=offset&0xffff;
  830.  offhi=offset>>16;
  831.  sizelo=size&0xffff;
  832.  sizehi=size>>16;
  833.  
  834. asm        mov    ax,offlo
  835. asm        or    ax,offhi
  836. asm        jz    CREATEIT
  837.  
  838. asm        mov    dx,filename
  839. asm        mov    ax,3d02h        // OPEN w/handle (read only)
  840. asm        int    21h
  841. asm        jc    out
  842.  
  843. asm        mov    handle,ax
  844.  
  845. asm        mov    bx,handle
  846. asm        mov     dx,offlo
  847. asm        mov    cx,offhi
  848. asm        mov    ax,4200h
  849. asm        int    21h            // SEEK (to file offset)
  850. asm        jc    out
  851.  
  852. asm        jmp    DOSAVE
  853.  
  854. CREATEIT:
  855.  
  856. asm        mov    dx,filename
  857. asm        mov    ax,3c00h        // CREATE w/handle (read only)
  858. asm        xor    cx,cx
  859. asm        int    21h
  860. asm        jc    out
  861.  
  862. asm        mov    handle,ax
  863.  
  864. DOSAVE:
  865.  
  866. asm        cmp    WORD PTR sizehi,0        // larger than 1 segment?
  867. asm        je    L2
  868.  
  869. L1:
  870.  
  871. asm        push    ds
  872. asm        mov    bx,handle
  873. asm        mov    cx,8000h
  874. asm        mov    dx,buf1
  875. asm        mov    ax,buf2
  876. asm        mov    ds,ax
  877. asm        mov    ah,40h            // WRITE w/handle
  878. asm        int    21h
  879. asm        pop    ds
  880.  
  881. asm        add    WORD PTR buf2,800h        // bump ptr up 1/2 segment
  882. asm        sub    WORD PTR sizelo,8000h        // done yet?
  883. asm        sbb    WORD PTR sizehi,0
  884. asm        cmp    WORD PTR sizehi,0
  885. asm        ja    L1
  886. asm        cmp    WORD PTR sizelo,8000h
  887. asm        jae    L1
  888.  
  889. L2:
  890.  
  891. asm        push    ds
  892. asm        mov    bx,handle
  893. asm        mov    cx,sizelo
  894. asm        mov    dx,buf1
  895. asm        mov    ax,buf2
  896. asm        mov    ds,ax
  897. asm        mov    ah,40h            // WRITE w/handle
  898. asm        int    21h
  899. asm        pop    ds
  900.  
  901. out:
  902.  
  903. asm        mov    bx,handle        // CLOSE w/handle
  904. asm        mov    ah,3eh
  905. asm        int    21h
  906.  
  907. }
  908.  
  909. ////////////////////////////////////////////////////////////
  910. //
  911. // Load a *LARGE* file into a FAR buffer!
  912. // by John Romero (C) 1991 Id Software
  913. //
  914. ////////////////////////////////////////////////////////////
  915. unsigned long LoadFile(char *filename,char huge *buffer,long offset,long size)
  916. {
  917.  unsigned handle,flength1=0,flength2=0,buf1,buf2,len1,len2,
  918.       rsize1,rsize2,roffset1,roffset2;
  919.  
  920.  rsize1=size&0xffff;
  921.  rsize2=size>>16;
  922.  roffset1=offset&0xffff;
  923.  roffset2=offset>>16;
  924.  buf1=FP_OFF(buffer);
  925.  buf2=FP_SEG(buffer);
  926.  
  927. asm        mov    dx,filename
  928. asm        mov    ax,3d00h        // OPEN w/handle (read only)
  929. asm        int    21h
  930. asm        jnc    L_0
  931. asm        jmp    out
  932.  
  933. L_0:
  934.  
  935. asm        mov    handle,ax
  936. asm        mov    bx,ax
  937. asm        xor    cx,cx
  938. asm        xor    dx,dx
  939. asm        mov    ax,4202h
  940. asm        int    21h            // SEEK (find file length)
  941. asm        jc    out
  942.  
  943. asm        mov    flength1,ax
  944. asm        mov    len1,ax
  945. asm        mov    flength2,dx
  946. asm        mov    len2,dx
  947.  
  948. asm        mov    ax,rsize1        // was a size specified?
  949. asm        or    ax,rsize1
  950. asm        jz    LOADALL
  951.  
  952. asm        mov    ax,rsize1        // only load size requested
  953. asm        mov    len1,ax
  954. asm        mov    ax,rsize2
  955. asm        mov    len2,ax
  956.  
  957. LOADALL:
  958.  
  959. asm        mov    bx,handle
  960. asm        mov     dx,roffset1
  961. asm        mov    cx,roffset2
  962. asm        mov    ax,4200h
  963. asm        int    21h            // SEEK (to file offset)
  964. asm        jc    out
  965.  
  966. asm        cmp    WORD PTR len2,0            // MULTI-SEGMENTAL?
  967. asm        je      L_2
  968.  
  969. L_1:
  970.  
  971. asm        push    ds
  972. asm        mov    bx,handle
  973. asm        mov    cx,8000h        // read 32K chunks
  974. asm        mov    dx,buf1
  975. asm        mov    ax,buf2
  976. asm        mov    ds,ax
  977. asm        mov    ah,3fh            // READ w/handle
  978. asm        int    21h
  979. asm        pop    ds
  980. asm        jc    out
  981.  
  982. asm        add    WORD PTR buf2,800h
  983. asm        sub    WORD PTR len1,8000h
  984. asm        sbb    WORD PTR len2,0
  985. asm        cmp    WORD PTR len2,0
  986. asm        ja    L_1
  987. asm        cmp    WORD PTR len1,8000h
  988. asm        jae    L_1
  989.  
  990. L_2:
  991.  
  992. asm        push    ds
  993. asm        mov    bx,handle
  994. asm        mov    cx,len1
  995. asm        mov    dx,buf1
  996. asm        mov    ax,buf2
  997. asm        mov    ds,ax
  998. asm        mov    ah,3fh            // READ w/handle
  999. asm        int    21h
  1000. asm        pop    ds
  1001. asm        jmp    exit
  1002.  
  1003. out:
  1004.  
  1005. asm        mov    WORD PTR flength2,0
  1006. asm        mov    WORD PTR flength1,0
  1007.  
  1008. exit:
  1009.  
  1010. asm        mov    bx,handle        // CLOSE w/handle
  1011. asm        mov    ah,3eh
  1012. asm        int    21h
  1013.  
  1014. return (flength2*0x10000+flength1);
  1015.  
  1016. }
  1017.  
  1018.  
  1019. ///////////////////////////////////////////////////
  1020. //
  1021. // error routine
  1022. //
  1023. ///////////////////////////////////////////////////
  1024. void errout(char *string)
  1025. {
  1026.  if (!noshow)
  1027.    {
  1028.     settext();
  1029.     DispStatusScreen();
  1030.    }
  1031.  
  1032.  window(1,1,79,24);
  1033.  sound(1500);
  1034.  gotoxy(1,24);
  1035.  printf("%s",string);
  1036.  poke(0,0x41a,peek(0,0x41c));    // clear keyboard
  1037.  DeleteTmpFiles();
  1038.  nosound();
  1039.  exit(1);
  1040. }
  1041.  
  1042.  
  1043. ///////////////////////////////////////////////////
  1044. //
  1045. // set a graphics mode
  1046. //
  1047. ///////////////////////////////////////////////////
  1048. void videomode(int planes)
  1049. {
  1050.  switch (planes)
  1051.    {
  1052.     case 2: { _AX=4; geninterrupt(0x10); break; }
  1053.     case 4: {
  1054.           _AX=0x0d;
  1055.           geninterrupt(0x10);
  1056.           break;
  1057.         }
  1058.     case 8: { _AX=0x13; geninterrupt(0x10); break; }
  1059.    }
  1060. }
  1061.  
  1062.  
  1063. ////////////////////////////////////////////////////
  1064. //
  1065. // Create an OBJ linkable file from any type of datafile
  1066. //
  1067. // Exit:
  1068. //  0 = everything's a-ok!
  1069. // -1 = file not found
  1070. // -2 = file >64K
  1071. //
  1072. ////////////////////////////////////////////////////
  1073. int MakeOBJ(char *filename,char *destfilename,char *public,segtype whichseg,char *farname)
  1074. {
  1075.  char THEADR[17]={0x80,14,0,12,32,32,32,32,32,32,32,32,32,32,32,32,0},
  1076.       COMENT[18]={0x88,0,0,0,0,'M','a','k','e','O','B','J',' ','v','1','.','1',0},
  1077.       LNAMES[42]={0x96,0,0,
  1078.           6,'D','G','R','O','U','P',
  1079.           5,'_','D','A','T','A',
  1080.           4,'D','A','T','A',
  1081.           0,
  1082.           5,'_','T','E','X','T',
  1083.           4,'C','O','D','E',
  1084.           8,'F','A','R','_','D','A','T','A'},
  1085.       SEGDEF[9]={0x98,7,0,0x48,0,0,2,3,4},    // for .DATA
  1086.       SEGDEF1[9]={0x98,7,0,0x48,0,0,5,6,4},    // for .CODE
  1087.       SEGDEF2[9]={0x98,7,0,0x60,0,0,8,7,4},    // for .FARDATA
  1088.       GRPDEF[7]={0x9a,4,0,1,0xff,1,0x61},
  1089.       MODEND[5]={0x8a,2,0,0,0x74};
  1090.  
  1091.  unsigned i,j,flag,handle;
  1092.  long fsize,offset,loffset,temp,amtleft,amount,offset1;
  1093.  char huge *dblock,huge *block;
  1094.  
  1095.  
  1096.  //
  1097.  // Need to compute the CHECKSUM in the COMENT field
  1098.  // (so if the "MakeOBJ..." string is modified, the CHECKSUM
  1099.  //  will be correct).
  1100.  //
  1101.  COMENT[1]=sizeof(COMENT)-3;
  1102.  for (flag=i=0;i<sizeof(COMENT);i++)
  1103.     flag+=COMENT[i];
  1104.  COMENT[sizeof(COMENT)-1]=(flag^0xff)+1;
  1105.  
  1106.  if ((handle=open(filename,O_BINARY))==NULL)
  1107.    return -1;
  1108.  
  1109.  fsize=filelength(handle);
  1110.  close(handle);
  1111.  if (fsize>0x10000L)        // BIGGER THAN 1 SEG = ERROR!
  1112.    return -2;
  1113.  
  1114.  block=(char huge *)farmalloc(fsize);
  1115.  if (block==NULL)
  1116.    errout("No memory to create OBJ!");
  1117.  LoadFile(filename,block,0,0);    // LOAD FILE IN
  1118.  offset=0;
  1119.  
  1120.  dblock=(char huge *)farmalloc(0x10000L);
  1121.  if (dblock==NULL)
  1122.    errout("No memory to create OBJ!");
  1123.  
  1124.  ////////////////////////////////////////////////////
  1125.  //
  1126.  // INSERT HEADER RECORD
  1127.  //
  1128.  movedata(_DS,FP_OFF(&THEADR),FP_SEG(dblock),FP_OFF(dblock)+offset,sizeof(THEADR));
  1129.  movedata(FP_SEG(filename),FP_OFF(filename),
  1130.       FP_SEG(dblock),FP_OFF(dblock)+offset+4,strlen(filename));
  1131.  offset+=sizeof(THEADR);
  1132.  
  1133.  
  1134.  ////////////////////////////////////////////////////
  1135.  //
  1136.  // INSERT COMMENT RECORD
  1137.  //
  1138.  movedata(_DS,FP_OFF(COMENT),FP_SEG(dblock),FP_OFF(dblock)+offset,sizeof(COMENT));
  1139.  offset+=sizeof(COMENT);
  1140.  
  1141.  
  1142.  ////////////////////////////////////////////////////
  1143.  //
  1144.  // INSERT START OF LIST-OF-NAMES RECORD
  1145.  //
  1146.  loffset=offset;
  1147.  movedata(_DS,FP_OFF(LNAMES),FP_SEG(dblock),FP_OFF(dblock)+offset,sizeof(LNAMES));
  1148.  offset+=sizeof(LNAMES);
  1149.  
  1150.  // If it's a .FARDATA segment, we need to insert the segment name!
  1151.  if (whichseg==FARDATA)
  1152.    {
  1153.     *(dblock+offset)=strlen(farname);
  1154.     movedata(FP_SEG(farname),FP_OFF(farname),
  1155.     FP_SEG(dblock),FP_OFF(dblock)+offset+1,strlen(farname));
  1156.     offset+=strlen(farname)+1;
  1157.    }
  1158.  
  1159.  // Now, finish the List-Of-Names record by creating
  1160.  // the CHECKSUM and LENGTH
  1161.  temp=offset;
  1162.  offset=offset-loffset-2;
  1163.  *(int huge *)(dblock+loffset+1)=offset;
  1164.  offset=temp;
  1165.  
  1166.  // Now, figure out the CHECKSUM of the record
  1167.  for (flag=i=0;i<(offset-loffset);i++)
  1168.    flag+=*(dblock+i+loffset);
  1169.  *(dblock+offset)=(flag^0xff)+1;
  1170.  offset++;
  1171.  
  1172.  
  1173.  ////////////////////////////////////////////////////
  1174.  //
  1175.  // CREATE SEGMENT DEFINITION RECORD
  1176.  //
  1177.  loffset=offset;
  1178.  temp=fsize;
  1179.  switch(whichseg)
  1180.  {
  1181.   case DATA:
  1182.     movedata(FP_SEG(&SEGDEF),FP_OFF(&SEGDEF),
  1183.          FP_SEG(dblock),FP_OFF(dblock)+offset,sizeof(SEGDEF));
  1184.     *(int huge *)(dblock+offset+4)=temp;
  1185.     offset+=sizeof(SEGDEF);
  1186.     break;
  1187.   case CODE:
  1188.     movedata(FP_SEG(&SEGDEF1),FP_OFF(&SEGDEF1),
  1189.          FP_SEG(dblock),FP_OFF(dblock)+offset,sizeof(SEGDEF1));
  1190.     *(int huge *)(dblock+offset+4)=temp;
  1191.     offset+=sizeof(SEGDEF1);
  1192.     break;
  1193.   case FARDATA:
  1194.     movedata(FP_SEG(&SEGDEF2),FP_OFF(&SEGDEF2),
  1195.          FP_SEG(dblock),FP_OFF(dblock)+offset,sizeof(SEGDEF2));
  1196.     *(int huge *)(dblock+offset+4)=temp;
  1197.     offset+=sizeof(SEGDEF2);
  1198.     break;
  1199.  }
  1200.  
  1201.  // CHECKSUM
  1202.  for (flag=0,i=loffset;i<offset;i++)
  1203.    flag+=*(dblock+i);
  1204.  *(dblock+offset)=(flag^0xff)+1;
  1205.  offset++;
  1206.  
  1207.  
  1208.  ////////////////////////////////////////////////////
  1209.  //
  1210.  // CREATE GROUP DEFINITION RECORD
  1211.  //
  1212.  switch(whichseg)
  1213.  {
  1214.   case DATA:
  1215.   case CODE:
  1216.     movedata(FP_SEG(&GRPDEF),FP_OFF(&GRPDEF),
  1217.          FP_SEG(dblock),FP_OFF(dblock)+offset,sizeof(GRPDEF));
  1218.     offset+=sizeof(GRPDEF);
  1219.  }
  1220.  
  1221.  
  1222.  ////////////////////////////////////////////////////
  1223.  //
  1224.  // CREATE PUBLIC DEFINITION RECORD
  1225.  //
  1226.  loffset=offset;
  1227.  *(dblock+offset)=0x90;        // PUBDEF ID
  1228.  offset+=3;            // point to public base, skip length
  1229.  *(dblock+offset)=1;        // group index=1
  1230.  *(dblock+offset+1)=1;        // segment index=1
  1231.  offset+=2;            // point to public name
  1232.  
  1233.  temp=0;
  1234.  movedata(FP_SEG(public),FP_OFF(public),
  1235.       FP_SEG(dblock),FP_OFF(dblock)+offset+1,strlen(public));
  1236.  *(dblock+offset)=strlen(public);
  1237.  offset+=strlen(public)+1;
  1238.  *(int huge *)(dblock+offset)=0;    // public offset within segment
  1239.  offset+=2;
  1240.  *(dblock+offset)=0;        // type index
  1241.  offset++;
  1242.  
  1243.  // LENGTH
  1244.  temp=offset-loffset-2;
  1245.  *(int huge *)(dblock+loffset+1)=temp;
  1246.  offset++;
  1247.  
  1248.  // CHECKSUM
  1249.  for (flag=0,i=loffset;i<offset;i++)
  1250.    flag+=*(dblock+i);
  1251.  *(dblock+offset)=(flag^0xff)+1;
  1252.  
  1253.  
  1254.  ////////////////////////////////////////////////////
  1255.  //
  1256.  // DATA RECORD(S). YUCK.
  1257.  //
  1258.  
  1259.  amtleft=fsize;
  1260.  amount=1024;
  1261.  for (i=0;i<(fsize+1023)/1024;i++)
  1262.    {
  1263.     offset1=offset;
  1264.     if (amtleft<1024)
  1265.       amount=amtleft;
  1266.     //
  1267.     // RECORD HEADER
  1268.     //
  1269.     *(dblock+offset)=0xa0;            // LEDATA ID
  1270.     *(int huge *)(dblock+offset+1)=amount+4;    // length of record
  1271.     offset+=3;
  1272.     *(dblock+offset)=1;                // segment index
  1273.     *(int huge *)(dblock+offset+1)=i*1024;    // index into segment
  1274.     offset+=3;
  1275.     //
  1276.     // LOAD DATA IN
  1277.     //
  1278.     LoadFile(filename,(char huge *)dblock+offset,i*1024,amount);
  1279.     offset+=amount;
  1280.     //
  1281.     // CHECKSUM!
  1282.     //
  1283.     for (flag=0,j=offset1;j<offset;j++)
  1284.       flag+=*(dblock+j);
  1285.     *(dblock+offset)=(flag^0xff)+1;
  1286.     offset++;
  1287.  
  1288.     amtleft-=1024;
  1289.    }
  1290.  
  1291.  ////////////////////////////////////////////////////
  1292.  //
  1293.  // MODULE END! YES!
  1294.  //
  1295.  movedata(FP_SEG(&MODEND),FP_OFF(&MODEND),FP_SEG(dblock),FP_OFF(dblock)+offset,sizeof(MODEND));
  1296.  offset+=sizeof(MODEND);
  1297.  
  1298.  //
  1299.  // Save the little puppy out!
  1300.  //
  1301.  SaveFile(destfilename,(char huge *)dblock,offset,0);
  1302.  farfree((void far *)block);
  1303.  farfree((void far *)dblock);
  1304.  return 0;
  1305. }
  1306.